import tkinter as tk
from tkinter import messagebox
import pymysql
import random
import time
import re

# ========== 配置部分 ==========
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '200412',
    'database': 'keshe',
    'port': 3306,
    'charset': 'utf8mb4'
}

# ========== 全局变量 ==========
current_code = ""
code_time = 0
code_expire = 300
last_send_time = 0
wrong_attempts = 0
lockout_until = 0

# ========== 正则表达式 ==========
PHONE_REGEX = r'^1[3-9]\d{9}$'
PID_REGEX = r'^\d{17}[\dXx]$'

# ========== 核心函数 ==========
def generate_code():
    return str(random.randint(100000, 999999))


def validate_input(phone=None, pid=None):
    if phone and not re.match(PHONE_REGEX, phone):
        messagebox.showerror("错误", "手机号应为11位数字且以13-19开头")
        return False
    if pid and not re.match(PID_REGEX, pid.upper()):
        messagebox.showerror("错误", "身份证号应为18位有效格式")
        return False
    return True


def show_frame(frame):
    frame.tkraise()


# ========== 验证码功能 ==========
def send_code(entry_phone, for_login=True):
    global current_code, code_time, last_send_time, lockout_until, wrong_attempts

    phone = entry_phone.get().strip()
    input_pid = entry_pid.get().strip().upper() if not for_login and 'entry_pid' in globals() else ""
    # 注册时同时校验身份证号 + 手机号格式
    if not for_login:
        if not validate_input(phone=phone, pid=input_pid):
            return
    else:
        if not validate_input(phone=phone):
            return

    now = time.time()
    if now < lockout_until:
        messagebox.showerror("锁定", f"请等待{int(lockout_until - now) // 60 + 1}分钟后再试")
        return
    if now - last_send_time < 60:
        messagebox.showwarning("提示", f"请等待{60 - int(now - last_send_time)}秒后重试")
        return

    try:
        conn = pymysql.connect(**DB_CONFIG)
        cursor = conn.cursor()
        cursor.execute("SELECT customerName,PID FROM userInfo WHERE telephone=%s", (phone,))
        result = cursor.fetchone()

        if for_login and not result:
            messagebox.showerror("错误", "账号不存在，请先注册")
            conn.close()
            return

        conn.close()

        if not for_login and result:
            input_pid = entry_pid.get().strip().upper() if 'entry_pid' in globals() else ""

            if not input_pid or not re.match(PID_REGEX, input_pid):
                messagebox.showerror("错误", "身份证号应为18位有效格式")
                conn.close()
                return

            if input_pid == result[1]:
                messagebox.showinfo("提示", f"用户【{result[0]}】已注册，请直接登录")
            else:
                messagebox.showerror("错误", "手机号已绑定其他身份证号，禁止注册")
            conn.close()
            return

            # 先校验身份证格式
            if not input_pid or not re.match(PID_REGEX, input_pid):
                messagebox.showerror("错误", "身份证号应为18位有效格式")
                return

            if input_pid and result[1] == input_pid:
                messagebox.showinfo("提示", f"用户【{result[0]}】已存在")
            else:
                messagebox.showerror("错误", "手机号已绑定其他身份证")
            return

        current_code = generate_code()
        code_time = now
        last_send_time = now
        wrong_attempts = 0
        messagebox.showinfo("验证码", f"验证码：{current_code}\n5分钟内有效")

    except Exception as e:
        messagebox.showerror("错误", f"数据库错误：{str(e)}")


# ========== 登录功能 ==========
def login():
    global wrong_attempts, lockout_until

    phone = entry_login_phone.get().strip()
    code = entry_login_code.get().strip()

    if not all([phone, code]):
        messagebox.showerror("错误", "请输入手机号和验证码")
        return
    if not validate_input(phone=phone):
        return

    now = time.time()
    if now < lockout_until:
        messagebox.showerror("锁定", "账号已锁定，请5分钟后再试")
        return
    if now - code_time > code_expire:
        messagebox.showerror("错误", "验证码已过期")
        return

    try:
        conn = pymysql.connect(**DB_CONFIG)
        cursor = conn.cursor()
        cursor.execute("SELECT customerID,customerName FROM userInfo WHERE telephone=%s", (phone,))
        result = cursor.fetchone()
        conn.close()

        if not result:
            messagebox.showerror("错误", "账号不存在")
            return
        if code != current_code:
            wrong_attempts += 1
            if wrong_attempts >= 5:
                lockout_until = now + 300
                messagebox.showerror("锁定", "错误次数过多，账号已锁定")
            else:
                messagebox.showerror("错误", f"验证码错误（剩余尝试：{5 - wrong_attempts}次）")
            return

        messagebox.showinfo("成功", f"欢迎回来，{result[1]}！")
        entry_login_phone.delete(0, tk.END)
        entry_login_code.delete(0, tk.END)

    except Exception as e:
        messagebox.showerror("错误", f"登录失败：{str(e)}")


# ========== 注册功能 ==========
def register():
    name = entry_name.get().strip()
    pid = entry_pid.get().strip().upper()
    phone = entry_phone.get().strip()
    address = entry_address.get().strip()
    code = entry_reg_code.get().strip()

    if not all([name, pid, phone, code]):
        messagebox.showerror("错误", "请填写完整信息")
        return
    if not validate_input(phone=phone, pid=pid):
        return
    if time.time() - code_time > code_expire:
        messagebox.showerror("错误", "验证码已过期")
        return

    try:
        conn = pymysql.connect(**DB_CONFIG)
        cursor = conn.cursor()

        cursor.execute("SELECT PID FROM userInfo WHERE telephone=%s", (phone,))
        if cursor.fetchone():
            messagebox.showerror("错误", "手机号已注册")
            conn.close()
            return

        cursor.execute("SELECT telephone FROM userInfo WHERE PID=%s", (pid,))
        if cursor.fetchone():
            messagebox.showerror("错误", "身份证号已注册")
            conn.close()
            return

        if code != current_code:
            messagebox.showerror("错误", "验证码错误")
            return

        cursor.execute(
            "INSERT INTO userInfo (customerName,PID,telephone,address) VALUES (%s,%s,%s,%s)",
            (name, pid, phone, address if address else None)
        )
        conn.commit()
        user_id = cursor.lastrowid
        conn.close()

        messagebox.showinfo("成功", f"注册成功！用户ID：{user_id}")
        for widget in [entry_name, entry_pid, entry_phone, entry_address, entry_reg_code]:
            widget.delete(0, tk.END)
        show_frame(login_frame)

    except Exception as e:
        messagebox.showerror("错误", f"注册失败：{str(e)}")


# ========== 界面构建 ==========
root = tk.Tk()
root.title("用户系统")
root.geometry("350x500")

# 登录界面
login_frame = tk.Frame(root)
tk.Label(login_frame, text="用户登录", font=("Arial", 16)).pack(pady=20)
tk.Label(login_frame, text="手机号：").pack()
entry_login_phone = tk.Entry(login_frame)
entry_login_phone.pack()
tk.Label(login_frame, text="验证码：").pack()
entry_login_code = tk.Entry(login_frame)
entry_login_code.pack()
tk.Button(login_frame, text="获取验证码", command=lambda: send_code(entry_login_phone, True)).pack(pady=5)
tk.Button(login_frame, text="登录", command=login).pack(pady=10)
label_to_register = tk.Label(login_frame, text="没有账号？注册", fg="blue", cursor="hand2")
label_to_register.pack()
label_to_register.bind("<Button-1>", lambda e: show_frame(register_frame))  # ⭐加上这行！
login_frame.grid(row=0, column=0, sticky="nsew")

# 注册界面
register_frame = tk.Frame(root)
tk.Label(register_frame, text="用户注册", font=("Arial", 16)).pack(pady=20)
tk.Label(register_frame, text="姓名：").pack()
entry_name = tk.Entry(register_frame)
entry_name.pack()
tk.Label(register_frame, text="身份证号：").pack()
entry_pid = tk.Entry(register_frame)
entry_pid.pack()
tk.Label(register_frame, text="手机号：").pack()
entry_phone = tk.Entry(register_frame)
entry_phone.pack()
tk.Label(register_frame, text="地址（可选）：").pack()
entry_address = tk.Entry(register_frame)
entry_address.pack()
tk.Label(register_frame, text="验证码：").pack()
entry_reg_code = tk.Entry(register_frame)
entry_reg_code.pack()
tk.Button(register_frame, text="获取验证码", command=lambda: send_code(entry_phone, False)).pack(pady=5)
tk.Button(register_frame, text="注册", command=register).pack(pady=10)
label_to_login = tk.Label(register_frame, text="已有账号？登录", fg="blue", cursor="hand2")
label_to_login.pack()
label_to_login.bind("<Button-1>", lambda e: show_frame(login_frame))  # ⭐加上这行！
register_frame.grid(row=0, column=0, sticky="nsew")


# 初始化显示登录界面
show_frame(login_frame)

root.mainloop()